Системное программирование

Организация  интерфейса  на основе меню

Системное программирование

Организация интерфейса на основе меню

Меню — это один из основных элементов пользовательского интерфейса в Windows-приложениях. Оно предоставляет пользователю доступ к функциям программы через иерархическую структуру команд. Меню может быть главным (располагаться в верхней части окна), контекстным (появляться при щелчке правой кнопкой мыши) или всплывающим (popup).

Организация  интерфейса  на основе меню
Системное программирование

1. Типы меню

1.1. Главное меню

Главное меню располагается в верхней части окна под заголовком. Оно содержит основные команды приложения, такие как "Файл", "Правка", "Вид" и т.д.

1.2. Контекстное меню

Контекстное меню появляется при щелчке правой кнопкой мыши на определённом элементе интерфейса. Оно содержит команды, актуальные для текущего контекста.

1.3. Всплывающее меню (Popup Menu)

Всплывающее меню — это меню, которое появляется в определённом месте экрана, например, при нажатии на кнопку.

Организация  интерфейса  на основе меню
Системное программирование

2. Создание меню

Меню в Windows-приложениях создается с помощью файла ресурсов (.rc) или программно в коде.

2.1. Создание меню в файле ресурсов

Пример создания главного меню в файле ресурсов:

Организация  интерфейса  на основе меню
Системное программирование
// Файл ресурсов (app.rc)
IDR_MAINMENU MENU
BEGIN
    POPUP "&Файл"
    BEGIN
        MENUITEM "&Открыть", ID_FILE_OPEN
        MENUITEM "&Сохранить", ID_FILE_SAVE
        MENUITEM SEPARATOR
        MENUITEM "В&ыход", ID_FILE_EXIT
    END
    POPUP "&Правка"
    BEGIN
        MENUITEM "&Вырезать", ID_EDIT_CUT
        MENUITEM "&Копировать", ID_EDIT_COPY
        MENUITEM "В&ставить", ID_EDIT_PASTE
    END
    POPUP "&Справка"
    BEGIN
        MENUITEM "&О программе", ID_HELP_ABOUT
    END
END
Организация  интерфейса  на основе меню
Системное программирование

2.2. Создание меню программно

Пример создания меню в коде:

HMENU hMenu = CreateMenu();
HMENU hFileMenu = CreatePopupMenu();
HMENU hEditMenu = CreatePopupMenu();

AppendMenu(hFileMenu, MF_STRING, ID_FILE_OPEN, "&Открыть");
AppendMenu(hFileMenu, MF_STRING, ID_FILE_SAVE, "&Сохранить");
AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hFileMenu, MF_STRING, ID_FILE_EXIT, "В&ыход");

AppendMenu(hEditMenu, MF_STRING, ID_EDIT_CUT, "&Вырезать");
AppendMenu(hEditMenu, MF_STRING, ID_EDIT_COPY, "&Копировать");
AppendMenu(hEditMenu, MF_STRING, ID_EDIT_PASTE, "В&ставить");

AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "&Файл");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hEditMenu, "&Правка");

SetMenu(hwnd, hMenu);
Организация  интерфейса  на основе меню
Системное программирование

3. Обработка команд меню

Команды меню обрабатываются в оконной процедуре (WndProc) с помощью сообщения WM_COMMAND.

Организация  интерфейса  на основе меню
Системное программирование

Пример обработки команд:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case ID_FILE_OPEN:
                    MessageBox(hwnd, "Команда: Открыть", "Меню", MB_OK);
                    break;
                case ID_FILE_SAVE:
                    MessageBox(hwnd, "Команда: Сохранить", "Меню", MB_OK);
                    break;
                case ID_FILE_EXIT:
                    PostQuitMessage(0);
                    break;
                case ID_EDIT_CUT:
                    MessageBox(hwnd, "Команда: Вырезать", "Меню", MB_OK);
                    break;
                case ID_EDIT_COPY:
                    MessageBox(hwnd, "Команда: Копировать", "Меню", MB_OK);
                    break;
                case ID_EDIT_PASTE:
                    MessageBox(hwnd, "Команда: Вставить", "Меню", MB_OK);
                    break;
                case ID_HELP_ABOUT:
                    MessageBox(hwnd, "О программе", "Меню", MB_OK);
                    break;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
Организация  интерфейса  на основе меню
Системное программирование

4. Контекстное меню

Контекстное меню создается аналогично главному меню, но отображается при щелчке правой кнопкой мыши.

Пример создания и отображения контекстного меню:

case WM_RBUTTONUP: {
    HMENU hMenu = CreatePopupMenu();
    AppendMenu(hMenu, MF_STRING, ID_CONTEXT_COPY, "Копировать");
    AppendMenu(hMenu, MF_STRING, ID_CONTEXT_PASTE, "Вставить");

    POINT pt;
    GetCursorPos(&pt);
    TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
    DestroyMenu(hMenu);
    break;
}
Организация  интерфейса  на основе меню
Системное программирование

5. Управление состоянием меню

Состояние пунктов меню (активен/неактивен, отмечен/не отмечен) можно изменять динамически.

5.1. Активация/деактивация пунктов меню

Пример:

EnableMenuItem(hMenu, ID_FILE_SAVE, MF_GRAYED); // Деактивировать пункт
EnableMenuItem(hMenu, ID_FILE_SAVE, MF_ENABLED); // Активировать пункт

5.2. Отметка пунктов меню

Пример:

CheckMenuItem(hMenu, ID_VIEW_TOOLBAR, MF_CHECKED); // Отметить пункт
CheckMenuItem(hMenu, ID_VIEW_TOOLBAR, MF_UNCHECKED); // Снять отметку
Организация  интерфейса  на основе меню
Системное программирование

6. Пример программы с меню

Рассмотрим пример простого Windows-приложения с главным меню.

Организация  интерфейса  на основе меню
Системное программирование

6.1. Файл ресурсов (app.rc)

IDR_MAINMENU MENU
BEGIN
    POPUP "&Файл"
    BEGIN
        MENUITEM "&Открыть", ID_FILE_OPEN
        MENUITEM "&Сохранить", ID_FILE_SAVE
        MENUITEM SEPARATOR
        MENUITEM "В&ыход", ID_FILE_EXIT
    END
    POPUP "&Правка"
    BEGIN
        MENUITEM "&Вырезать", ID_EDIT_CUT
        MENUITEM "&Копировать", ID_EDIT_COPY
        MENUITEM "В&ставить", ID_EDIT_PASTE
    END
END
Организация  интерфейса  на основе меню
Системное программирование

6.2. Код программы (main.c)

#include <windows.h>

#define ID_FILE_OPEN 101
#define ID_FILE_SAVE 102
#define ID_FILE_EXIT 103
#define ID_EDIT_CUT 201
#define ID_EDIT_COPY 202
#define ID_EDIT_PASTE 203

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case ID_FILE_OPEN:
                    MessageBox(hwnd, "Открыть файл", "Меню", MB_OK);
                    break;
                case ID_FILE_SAVE:
                    MessageBox(hwnd, "Сохранить файл", "Меню", MB_OK);
                    break;
                case ID_FILE_EXIT:
                    PostQuitMessage(0);
                    break;
                case ID_EDIT_CUT:
                    MessageBox(hwnd, "Вырезать", "Меню", MB_OK);
                    break;
                case ID_EDIT_COPY:
                    MessageBox(hwnd, "Копировать", "Меню", MB_OK);
                    break;
                case ID_EDIT_PASTE:
                    MessageBox(hwnd, "Вставить", "Меню", MB_OK);
                    break;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

Организация  интерфейса  на основе меню
Системное программирование

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "MyWindowClass";
    RegisterClass(&wc);

    HWND hwnd = CreateWindow("MyWindowClass", "Окно с меню", WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}
Организация  интерфейса  на основе меню